#include "MpiCommunicator.h"
#include "MpiException.h"
#include "MpiDataType.h"

using namespace SG::Algebra;

//=============================================================================
// MpiCommunicator

MpiCommunicator::MpiCommunicator () 
    : mComm (MPI_COMM_WORLD)
{

}

MpiCommunicator::MpiCommunicator (const MPI_Comm& comm)
    : mComm (comm)
{
}

MpiCommunicator::~MpiCommunicator ()
{
}

int MpiCommunicator::rank ()
{
    int rank;

    MPI_CHECK_RESULT (MPI_Comm_rank, (mComm, &rank));

    return rank;
}

int MpiCommunicator::size ()
{
    int size;

    MPI_CHECK_RESULT (MPI_Comm_size, (mComm, &size));

    return size;
}

template <typename TDataType>
void MpiCommunicator::send (int dest, int tag, TDataType* buffer, int count)
{
    MPI_Send (buffer, count, MpiDataType<TDataType>::mpi_type, dest, tag, mComm);
}

template <typename TDataType>
void MpiCommunicator::recv (int source, int tag, TDataType* buffer, int count)
{
    MPI_Status status;
    MPI_CHECK_RESULT (MPI_Recv, (( void* ) buffer, count, MpiDataType<TDataType>::mpi_type, source, tag, mComm, &status));
}

template <typename TDataType>
void MpiCommunicator::bcast (int root, TDataType* buffer, int count)
{
    MPI_CHECK_RESULT (MPI_Bcast, (( void* ) buffer, count, MpiDataType<TDataType>::mpi_type, root, mComm));
}

void MpiCommunicator::barrier ()
{
    MPI_CHECK_RESULT (MPI_Barrier, (mComm));
}

//=========================================================================================================================
// Explicit specialization for common data types
//=========================================================================================================================

template void MpiCommunicator::send<int> (int dest, int tag, int* buffer, int count);
template void MpiCommunicator::recv<int> (int source, int tag, int* buffer, int count);

template void MpiCommunicator::send<float> (int dest, int tag, float* buffer, int count);
template void MpiCommunicator::recv<float> (int source, int tag, float* buffer, int count);

template void MpiCommunicator::send<double> (int dest, int tag, double* buffer, int count);
template void MpiCommunicator::recv<double> (int source, int tag, double* buffer, int count);
